home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 March / CMCD0305.ISO / Software / Shareware / Utilitare / emu / Emu8086_Setup_307c.exe / {app} / Samples / float.asm < prev    next >
Assembly Source File  |  2002-08-02  |  12KB  |  461 lines

  1.           TITLE   CALCULATE EQUATION
  2.           
  3. ;     AUTHOR  Yuri Margolin
  4. ;             http://mysoft.s5.com/
  5.  
  6. ;     DATE    24/01/01
  7. ;     VERSION 1.12
  8.  
  9. ; This program calculates
  10. ; linear equation: ax + b = 0
  11. ; The result is printed with
  12. ; floating point.
  13. ; For example: a = 7, b = 2
  14. ;              x = -0.28571428....
  15.  
  16. ; Directive to select
  17. ; "make EXE" by default when
  18. ; source file is compiled:
  19.    #MAKE_EXE#
  20.    
  21.    
  22. DSEG    SEGMENT 'DATA'
  23. CR              EQU     13
  24. LF              EQU     10
  25. NEW_LINE        EQU     13, 10, '$'
  26. MESS0           DB      'Calculation of ax + b = 0', NEW_LINE
  27. MESS1           DB      'ENTER a (-32768..32767)!', NEW_LINE
  28. MESS2           DB      LF, CR, 'ENTER b (-32768..32767)!', NEW_LINE
  29. MESS3           DB      CR, LF, CR, LF, 'Data:', '$'
  30. MESS4           DB      CR, LF, ' a = ', '$'
  31. MESS5           DB      CR, LF, ' b = ', '$'
  32. MESS6           DB      CR, LF, 'Result: ', CR, LF, ' x = ', '$'
  33. MESS7           DB      CR, LF, CR, LF, 'NO SOLUTION!', NEW_LINE
  34. MESS8           DB      CR, LF, CR, LF, 'INFINITE NUMBER OF SOLUTIONS!', NEW_LINE
  35. ERROR           DB      CR, LF, 'THE NUMBER IS OUT OF RANGE!', NEW_LINE
  36. TWICE_NL        DB      NEW_LINE, NEW_LINE 
  37. make_minus      DB      ?       ; used as a flag in procedures.
  38. a               DW      ?
  39. b               DW      ?
  40. ten             DW      10      ; used as multiplier.
  41. four            DW      4       ; used as divider.
  42. DSEG    ENDS
  43.  
  44. SSEG    SEGMENT STACK   'STACK'
  45.                 DW      100h    DUP(?)
  46. SSEG    ENDS
  47.  
  48. CSEG    SEGMENT 'CODE'
  49.  
  50. ;*******************************************************************
  51.  
  52. START           PROC    FAR
  53.  
  54. ; Store return address to OS:
  55.                 PUSH    DS
  56.                 XOR     AX, AX
  57.                 PUSH    AX
  58.                 
  59. ; Set segment registers:                
  60.                 MOV     AX, DSEG
  61.                 MOV     DS, AX
  62.                 MOV     ES, AX
  63.  
  64. ; Welcome message:
  65.                 LEA     DX, MESS0
  66.                 CALL    PUTS            ; Display the message.
  67.  
  68. ; Ask for 'a' :
  69.                 LEA     DX, MESS1
  70.                 CALL    PUTS            ; Display the message.
  71.                 CALL    SCAN_NUM        ; Input the number into CX.
  72.                 MOV     a, CX
  73.  
  74. ; Ask for 'b' :
  75.                 LEA     DX, MESS2
  76.                 CALL    PUTS            ; Display the message.
  77.                 CALL    SCAN_NUM        ; Input the number into CX.
  78.                 MOV     b, CX
  79.  
  80. ; Print the data:
  81.                 LEA     DX, MESS3
  82.                 CALL    PUTS
  83.  
  84.                 LEA     DX, MESS4
  85.                 CALL    PUTS
  86.                 MOV     AX, a
  87.                 CALL    PRINT_NUM               ; print AX.
  88.  
  89.                 LEA     DX, MESS5
  90.                 CALL    PUTS
  91.                 MOV     AX, b
  92.                 CALL    PRINT_NUM               ; print AX.
  93.  
  94.  
  95. ; Check data:
  96.                 CMP     a, 0
  97.                 JNE     soluble         ; jumps when a<>0.
  98.                 CMP     b, 0
  99.                 JNE     no_solution     ; jumps when a=0 AND b<>0.
  100.                 JMP     infinite        ; jumps when a=0 AND b=0.
  101. soluble:
  102.  
  103. ; Calculate the solution:
  104. ; ax + b = 0  ->  ax = -b  ->  x = -b/a
  105.  
  106.                 NEG     b
  107.  
  108.                 MOV     AX, b
  109.  
  110.                 XOR     DX, DX
  111.  
  112.                 ; check the sign, make DX:AX negative if AX is negative:
  113.                 CMP     AX, 0
  114.                 JNS     not_singned
  115.                 NOT     DX
  116. not_singned:
  117.                 MOV     BX, a   ; divider is in BX.
  118.  
  119.                 ; '-b' is in DX:AX.
  120.                 ; 'a' is in BX.
  121.  
  122.                 IDIV    BX      ; AX = DX:AX / BX       (DX - remainder).
  123.  
  124.                 ; 'x' is in AX.
  125.                 ; remainder is in DX.
  126.  
  127.                 PUSH    DX      ; store the remainder.
  128.  
  129.                 LEA     DX, MESS6
  130.                 CALL    PUTS
  131.  
  132.                 POP     DX
  133.  
  134.                 ; print 'x' as float:
  135.                 ; AX - whole part
  136.                 ; DX - remainder
  137.                 ; BX - divider
  138.                 CALL    PRINT_FLOAT
  139.  
  140.                 JMP     end_prog
  141. no_solution:
  142.                 LEA     DX, MESS7
  143.                 CALL    PUTS
  144.                 JMP     end_prog
  145. infinite:
  146.                 LEA     DX, MESS8
  147.                 CALL    PUTS
  148. end_prog:
  149.                 LEA     DX, TWICE_NL
  150.                 CALL    PUTS
  151.                 
  152.                 RET
  153.  START          ENDP
  154.  
  155. ;***************************************************************
  156.  
  157. ; Prints number in AX and it's fraction in DX.
  158. ; used to print remainder of 'DIV/IDIV BX'.
  159. ; AX - whole part.
  160. ; DX - remainder.
  161. ; BX - the divider that was used to get the remainder from divident.
  162. PRINT_FLOAT     PROC    NEAR
  163.         PUSH    CX
  164.         PUSH    DX
  165.  
  166.         ; because the remainder takes the sign of divident
  167.         ; its sign should be inverted when divider is negative
  168.         ; (-) / (-) = (+)
  169.         ; (+) / (-) = (-)
  170.         CMP     BX, 0
  171.         JNS     div_not_signed
  172.         NEG     DX              ; make remainder positive.
  173. div_not_signed:
  174.  
  175.         ; PRINT_NUM procedure does not print the '-'
  176.         ; when the whole part is '0' (even if the remainder is
  177.         ; negative) this code fixes it:
  178.         CMP     AX, 0
  179.         JNE     checked         ; AX<>0
  180.         CMP     DX, 0
  181.         JNS     checked         ; AX=0 and DX>=0
  182.         PUSH    DX
  183.         MOV     DL, '-'
  184.         CALL    WRITE_CHAR      ; print '-'
  185.         POP     DX
  186. checked:
  187.  
  188.         ; print whole part:
  189.         CALL    PRINT_NUM
  190.  
  191.         ; if remainder=0, then no need to print it:
  192.         CMP     DX, 0
  193.         JE      done
  194.  
  195.         PUSH    DX
  196.         ; print dot after the number:
  197.         MOV     DL, '.'
  198.         CALL    WRITE_CHAR
  199.         POP     DX
  200.  
  201.         ; print digits after the dot:
  202.         MOV     CX, 15  ; max digits after the dot.
  203.         CALL    PRINT_FRACTION
  204. done:
  205.         POP     DX
  206.         POP     CX
  207.         RET
  208. PRINT_FLOAT     ENDP
  209.  
  210. ;***************************************************************
  211.  
  212. ; Prints DX as fraction of division by BX.
  213. ; DX - remainder.
  214. ; BX - divider.
  215. ; CX - maximum number of digits after the dot.
  216. PRINT_FRACTION  PROC    NEAR
  217.         PUSH    AX
  218.         PUSH    DX
  219. next_fraction:
  220.         ; check if all digits are already printed:
  221.         CMP     CX, 0
  222.         JZ      end_rem
  223.         DEC     CX      ; decrease digit counter.
  224.  
  225.         ; when remainder is '0' no need to continue:
  226.         CMP     DX, 0
  227.         JE      end_rem
  228.  
  229.         MOV     AX, DX
  230.         XOR     DX, DX
  231.         CMP     AX, 0
  232.         JNS     not_sig1
  233.         NOT     DX
  234. not_sig1:
  235.  
  236.         IMUL    ten             ; DX:AX = AX * 10
  237.  
  238.         IDIV    BX              ; AX = DX:AX / BX   (DX - remainder)
  239.  
  240.         PUSH    DX              ; store remainder.
  241.         MOV     DX, AX
  242.         CMP     DX, 0
  243.         JNS     not_sig2
  244.         NEG     DX
  245. not_sig2:
  246.         ADD     DL, 30h         ; convert to ASCII code.
  247.         CALL    WRITE_CHAR      ; print DL.
  248.         POP     DX
  249.  
  250.         JMP     next_fraction
  251. end_rem:
  252.         POP     DX
  253.         POP     AX
  254.         RET
  255. PRINT_FRACTION  ENDP
  256.  
  257. ;***************************************************************
  258.  
  259. ; This procedure prints number in AX,
  260. ; used with PRINT_NUMX to print "0" and sign.
  261. ; this procedure also stores the original AX,
  262. ; that is modified by PRINT_NUMX.
  263. PRINT_NUM       PROC    NEAR
  264.         PUSH    DX
  265.         PUSH    AX
  266.  
  267.         CMP     AX, 0
  268.         JNZ     not_zero
  269.  
  270.         MOV     DL, '0'
  271.         CALL    WRITE_CHAR
  272.         JMP     printed
  273.  
  274. not_zero:
  275.         ; the check SIGN of AX,
  276.         ; make absolute if it's negative:
  277.         CMP     AX, 0
  278.         JNS     positive
  279.         NEG     AX
  280.  
  281.         MOV     DL, '-'
  282.         CALL    WRITE_CHAR
  283. positive:
  284.         CALL    PRINT_NUMX
  285. printed:
  286.         POP     AX
  287.         POP     DX
  288.         RET
  289. PRINT_NUM       ENDP
  290.  
  291. ;***************************************************************
  292.  
  293. ; Prints out a number in AX (not just a single digit)
  294. ; allowed values from 1 to 65535 (FFFF)
  295. ; (result of /10000 should be the left digit or "0").
  296. ; modifies AX (after the procedure AX=0)
  297. PRINT_NUMX      PROC    NEAR
  298.         PUSH    BX
  299.         PUSH    CX
  300.         PUSH    DX
  301.  
  302.         ; flag to prevent printing zeros before number:
  303.         MOV     CX, 1
  304.  
  305.         MOV     BX, 10000       ; 2710h - divider.
  306.  
  307.         ; Check if AX is zero, if zero go to end_show
  308.         CMP     AX, 0
  309.         JZ      end_show
  310.  
  311. begin_print:
  312.  
  313.         ; check divider (if zero go to end_show):
  314.         CMP     BX,0
  315.         JZ      end_show
  316.  
  317.         ; avoid printing zeros before number:
  318.         CMP     CX, 0
  319.         JE      calc
  320.         ; if AX<BX then result of DIV will be zero:
  321.         CMP     AX, BX
  322.         JB      skip
  323. calc:
  324.         XOR     CX, CX  ; set flag.
  325.  
  326.         XOR     DX, DX
  327.         DIV     BX      ; AX = DX:AX / BX   (DX=remainder).
  328.  
  329.         ; print last digit
  330.         ; AH is always ZERO, so it's ignored
  331.         PUSH    DX
  332.         MOV     DL, AL
  333.         ADD     DL, 30h    ; convert to ASCII code.
  334.         CALL    WRITE_CHAR
  335.         POP     DX
  336.  
  337.         MOV     AX, DX  ; get remainder from last div.
  338.  
  339. skip:
  340.         ; calculate BX=BX/10
  341.         PUSH    AX
  342.         XOR     DX, DX
  343.         MOV     AX, BX
  344.         DIV     ten     ; AX = DX:AX / 10   (DX=remainder).
  345.         MOV     BX, AX
  346.         POP     AX
  347.  
  348.         JMP     begin_print
  349.  
  350. end_show:
  351.  
  352.         POP     DX
  353.         POP     CX
  354.         POP     BX
  355.         RET
  356. PRINT_NUMX      ENDP
  357.  
  358. ;***************************************************************
  359.  
  360. ; Displays the message (DX-address)
  361. PUTS    PROC    NEAR
  362.         PUSH    AX
  363.         MOV     AH, 09h
  364.         INT     21h
  365.         POP     AX
  366.         RET
  367. PUTS    ENDP
  368.  
  369. ;*******************************************************************
  370.  
  371. ; Reads char from the keyboard into AL
  372. ; (MODIFIES AX!!!)
  373. READ_CHAR       PROC    NEAR
  374.         MOV     AH, 01h
  375.         INT     21h
  376.         RET
  377. READ_CHAR       ENDP
  378.  
  379. ;***************************************************************
  380.  
  381. ; Gets the multi-digit SIGNED number from the keyboard,
  382. ; Result is stored in CX
  383. SCAN_NUM        PROC    NEAR
  384.         PUSH    DX
  385.         PUSH    AX
  386.  
  387.         XOR     CX, CX
  388.  
  389.         ; reset flag:
  390.         MOV     make_minus, 0
  391.  
  392. next_digit:
  393.  
  394.         CALL    READ_CHAR
  395.  
  396.         ; check for MINUS:
  397.         CMP     AL, '-'
  398.         JE      set_minus
  399.  
  400.         ; check for ENTER key:
  401.         CMP     AL, CR
  402.         JE      stop_input
  403.  
  404.         ; multiply CX by 10 (first time the result is zero)
  405.         PUSH    AX
  406.         MOV     AX, CX
  407.         MUL     ten                     ; DX:AX = AX*10
  408.         MOV     CX, AX
  409.         POP     AX
  410.  
  411.         ; check if the number is too big
  412.         ; (result should be 16 bits)
  413.         CMP     DX, 0
  414.         JNE     out_of_range
  415.  
  416.         ; convert from ASCII code:
  417.         SUB     AL, 30h
  418.  
  419.         ; add AL to CX:
  420.         XOR     AH, AH
  421.         ADD     CX, AX
  422.         JC      out_of_range    ; jump if the number is too big.
  423.  
  424.         JMP     next_digit
  425.  
  426. set_minus:
  427.         MOV     make_minus, 1
  428.         JMP     next_digit
  429.  
  430. out_of_range:
  431.         LEA     DX, ERROR
  432.         CALL    PUTS
  433.  
  434. stop_input:
  435.         ; check flag:
  436.         CMP     make_minus, 0
  437.         JE      not_minus
  438.         NEG     CX
  439. not_minus:
  440.  
  441.         POP     AX
  442.         POP     DX
  443.         RET
  444. SCAN_NUM        ENDP
  445.  
  446. ;***************************************************************
  447.  
  448. ; Prints out single char (ascii code should be in DL)
  449. WRITE_CHAR      PROC    NEAR
  450.         PUSH    AX
  451.         MOV     AH, 02h
  452.         INT     21h
  453.         POP     AX
  454.         RET
  455. WRITE_CHAR      ENDP
  456.  
  457. ;***************************************************************
  458.  
  459. CSEG    ENDS
  460.         END     START
  461.